package pam.web;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import pam.core.IFile;
import pam.core.LoggerFactory;
import pam.core.UUID;
import pam.core.XMLObject;
import pam.security.IGuard;
import pam.security.NoAuthorizationException;

/**
 * PAM抽象Servlet类.
 */
public abstract class AbstractServlet extends HttpServlet {

	private static final long serialVersionUID = 7288327368799712656L;
	private Map cache;

	public void init() throws ServletException {
		super.init();
		if (isUseCache()) {
			cache = new ConcurrentHashMap(getCacheSize());
		}
	}

	protected void doGet(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {

		doPost(request, response);
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		IPamletFactory factory = getFactory();

		if (factory == null) {
			throw new ServletException("初始化错误!");
		}
		/** 设置输入输出* */
		request.setCharacterEncoding("UTF-8");
		response.setCharacterEncoding("UTF-8");

		/** 解析服务请求并转发调用相应的方法实例 */

		Parameters map = null;
		IRequestParser requestParser;
		if (request.getParameter(IPamletFactory.pamletID) != null) {
			// 正常提交
			requestParser = new PlainRequestParser();
		} else {
			requestParser = new MultiPartRequestParser();
		}

		if (requestParser == null) {
			printErrorMessage("提交参数设置有误, 未设置服务标识", response);
			return;
		}

		try {
			map = requestParser.parse(request);
		} catch (WebException e) {
			printErrorMessage("提交参数设置有误!", response);
			return;
		}

		if (map == null) {
			printErrorMessage("提交参数设置有误2!", response);
			return;
		}

		AbstractPamlet function = null;
		try {
			String functionName = map.getString(IPamletFactory.pamletID);
			function = factory.getPamlet(functionName);
		} catch (WebException e) {
			printErrorMessage(e.getMessage(), response);
			return;
		}

		if (function != null) {

			/** 权限检查 **/
			IGuard guard = getGuard();
			if (guard != null) {
				try {
					if (!guard.checkAccess(function, request.getRemoteUser())) {
						Message objMessage = new Message("该操作未授权!");
						printInformation(objMessage, response);
						return;
					}
				} catch (NoAuthorizationException e) {
					Message objMessage = new Message("该操作未授权!");
					printInformation(objMessage, response);
					return;
				}
			}
			/*************/

			XMLObject xmlObject = null;
			try {
				function.setParameters(map);
				function.setCache(cache);
				function.setSession(request.getSession());
				function.setLoginUsername(request.getRemoteUser());
				prepareComponents();
				function.setComponents(components);
				xmlObject = function.execute();
			} catch (WebException e) {
				printErrorMessage(e.getMessage(), response);
				return;
			} catch (Exception e) {
				e.printStackTrace();
				LoggerFactory.getLogger().severe("出现运行时异常:" + e.getMessage());
				printErrorMessage("系统错误!", response);
				return;
			}

			// 以下输出都是正常情况下，如果操作失败，Function实例会封装成ServletException并抛出，从而使用printErrorMessage
			if (xmlObject == null) {// 查询结果为空
				Message objMessage = new Message("没有找到符合条件的结果!");
				printResult(objMessage, response);
			} else if (xmlObject instanceof Message) {// 增、删、改操作正常
				printInformation((Message) xmlObject, response);
			} else if (xmlObject instanceof IFile) {// 查询结果为文件
				IFile file = (IFile) xmlObject;
				printImage(file != null ? file.getContent() : null, response);
			} else if (xmlObject instanceof UUID) {
				UUID uuid = (UUID) xmlObject;
				printString(uuid.getId(), response);
			} else {// 查询
				printResult(xmlObject, response);
			}

			return;

		}

		printErrorMessage("提交参数设置有误, 请求功能未找到!", response);
		return;
	}

	protected abstract IPamletFactory getFactory();

	protected abstract IGuard getGuard();

	protected boolean isUseCache() {
		return false;
	}

	protected int getCacheSize() {
		return 1000;
	}

	protected void printErrorMessage(String message,
			HttpServletResponse response) {
		Message msg = new Message(message);
		msg.setCode(0);
		printXML(msg.toXML(), response);
	}

	protected void printInformation(String message, HttpServletResponse response) {
		Message msg = new Message(message);
		printXML(msg.toXML(), response);
	}

	protected void printInformation(Message msg, HttpServletResponse response) {
		printXML(msg.toXML(), response);
	}

	protected void printResult(XMLObject object, HttpServletResponse response) {
		if (object == null) {
			return;
		}
		printXML(object.toXML(), response);
	}

	protected void printPDF(byte[] pdf, HttpServletResponse response) {
		response.setContentType("application/pdf");

		printBinary(pdf, response);
	}

	protected void printImage(byte[] image, HttpServletResponse response) {
		response.setContentType("image/jpeg");

		printBinary(image, response);
	}

	protected void printXML(String xml, HttpServletResponse response) {

		PrintWriter writer = null;
		response.setContentType("text/xml");
		try {
			writer = response.getWriter();
			writer.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
			writer.println(xml);
			writer.flush();
			writer.close();

		} catch (IOException e) {
			LoggerFactory.getLogger().severe(e.getMessage());
		} finally {
			if (writer != null) {
				writer.close();
			}
		}
	}

	protected void printString(String s, HttpServletResponse response) {

		PrintWriter writer = null;
		response.setContentType("text/xml");
		try {
			writer = response.getWriter();
			writer.println(s);
			writer.flush();
			writer.close();

		} catch (IOException e) {
			LoggerFactory.getLogger().severe(e.getMessage());
		} finally {
			if (writer != null) {
				writer.close();
			}
		}
	}

	protected InitialContext getContext() {
		// if (context == null) {
		// try {
		// context = new InitialContext();
		// getServletContext().setAttribute(attribute_context, context);
		// } catch (NamingException e) {
		// // TODO Auto-generated catch block
		// e.printStackTrace();
		// }
		//
		// }

		// return context;

		try {
			return new InitialContext();
		} catch (NamingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return null;
	}

	private void printBinary(byte[] binary, HttpServletResponse response) {
		if (binary == null) {
			return;
		}
		OutputStream out = null;
		ByteArrayInputStream bi = null;
		try {
			out = response.getOutputStream();
			bi = new ByteArrayInputStream(binary);
			int count = 0;
			byte[] b = new byte[2048];
			while ((count = bi.read(b, 0, 2048)) != -1) {
				out.write(b, 0, count);
			}

		} catch (Exception e) {
			LoggerFactory.getLogger().severe(e.getMessage());
		} finally {
			try {
				if (bi != null) {
					bi.close();
				}
				if (out != null) {
					out.close();
				}
			} catch (Exception e) {
				LoggerFactory.getLogger().severe(e.getMessage());
			}
		}
	}

	final protected void initComponent(String jndi, Object component) {
		if (components == null) {
			components = new ConcurrentHashMap();
		}

		components.put(jndi, component);

	}

	protected void prepareComponents() {

	}

	private Map components;

}
